package com.xunwulian.cmpp.server.handler;

import com.xunwulian.base.constant.ConstantBean;
import com.xunwulian.cmpp.Tools;
import com.xunwulian.cmpp.pdu.ActiveTest;
import com.xunwulian.cmpp.pdu.ActiveTestResp;
import com.xunwulian.cmpp.pdu.CmppPDU;
import com.xunwulian.cmpp.pdu.Connect;
import com.xunwulian.cmpp.pdu.ConnectResp;
import com.xunwulian.cmpp.pdu.Deliver;
import com.xunwulian.cmpp.pdu.DeliverResp;
import com.xunwulian.cmpp.pdu.Submit;
import com.xunwulian.cmpp.pdu.SubmitResp;
import com.xunwulian.cmpp.sms.ByteBuffer;
import com.xunwulian.cmpp.sms.ShortMessage;
import com.xunwulian.cmpp.util.CmppConstant;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class CmppServerIoHandler extends IoHandlerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(CmppServerIoHandler.class);

    public static boolean isConnect = false;
    public static boolean isFirstMsg = true;

    public CmppServerIoHandler() {
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        logger.info("Session " + session.getId() + " is opened");

        Thread t = new Thread(new ActiveThread(session));
        t.setDaemon(true);
        t.start();
        session.resumeRead();
    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {
        logger.info("Creation of session " + session.getId());
        session.setAttribute(ConstantBean.OPEN);
        session.suspendRead();

    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        session.removeAttribute(ConstantBean.OPEN);
        logger.info("Session closed, session.getId() : [%d]", session.getId());
    }

    @Override
    public void exceptionCaught(IoSession session, Throwable cause) {
        logger.info("exceptionCaught:" + cause.getMessage());
        if (!(cause instanceof IOException)) {
            logger.error("Exception: ", cause);
        } else {
            logger.info("I/O error: " + cause.getMessage());
        }
        session.close(true);
    }

//    @Override
//    public void inputClosed(IoSession session) throws Exception {
//        super.inputClosed(session);
//        logger.info("input closed" + session.getId());
//    }

    @Override
    public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
        super.sessionIdle(session, status);
        logger.info("sessionIdle " + status.toString());
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        super.messageSent(session, message);
        logger.info("message sent:" + message.toString());
    }

    @Override
    public void messageReceived(IoSession session, Object message) {
        CmppPDU pdu = (CmppPDU) message;
        if (isFirstMsg == true || isConnect == true) {
            isFirstMsg = false;
            int cmd = pdu.header.getCommandId();

            if (cmd == CmppConstant.CMD_CONNECT) {
                Connect con = (Connect) pdu;
                logger.info("session id: [" + session.getId() + "], receive Connect:[" + con.dump() + "]");
                ConnectResp conresp = (ConnectResp) con.getResponse();
                session.write(conresp);
                logger.info("session id: [" + session.getId() + "], write ConnectResp:[" + conresp.dump() + "]");
                isConnect = true;

            } else if (cmd == CmppConstant.CMD_ACTIVE_TEST) {
                ActiveTest activeTest = (ActiveTest) pdu;
                logger.info("session id: [" + session.getId() + "], 接收到心跳请求，receive ActiveTest");
                ActiveTestResp activeTestResp = (ActiveTestResp) activeTest.createResponse();
                session.write(activeTestResp);
                logger.info("session id: [" + session.getId() + "], 发送心跳应答，write ActiveTestResp");

            } else if (cmd == CmppConstant.CMD_ACTIVE_TEST_RESP) {
                ActiveTestResp activeTestRsp = (ActiveTestResp) pdu;
                logger.info("session id: [" + session.getId() + "], 接收到心跳应答，receive ActiveTestResp");
                ActiveThread.lastActiveTime = System.currentTimeMillis();
            } else {
                switch (pdu.header.getCommandId()) {
                    case CmppConstant.CMD_SUBMIT:
                        Submit submit = (Submit) pdu;
                        logger.info("session id: [" + session.getId() + "], receive submit:[" + submit.dump() + "]");
                        SubmitResp subresp = (SubmitResp) submit.createResponse();
                        subresp.setMsgId(Tools.GetRspid());
                        session.write(subresp);
                        logger.info("session id: [" + session.getId() + "], write subresp:[" + subresp.dump() + "]");
                        Deliver deliver = sendMsgStat(submit);

                        session.write(deliver);
                        logger.info("session id: [" + session.getId() + "], write deliver:[" + deliver.dump() + "]");
                        break;

                    case CmppConstant.CMD_DELIVER_RESP:
                        DeliverResp delresp = (DeliverResp) pdu;
                        logger.info("session id: [" + session.getId() + "], receive delresp:[" + delresp.dump() + "]");
                        break;

                    default:
                        logger.warn("Unexpected PDU received! PDU Header: " + pdu.header.getData().hexDump());
                        break;
                }
            }
        }
    }

    private Deliver sendMsgStat(Submit submit) {

        // TODO Auto-generated method stub
        Deliver delive = new Deliver();

        delive.setMsgId(Tools.GetMsgid());
        delive.setDstId(submit.getMsgSrc());
        delive.setServiceId(submit.getServiceId());
        delive.setSrcTermId(submit.getDestTermId()[0]);
        delive.setIsReport((byte) 1);

        ShortMessage sm = new ShortMessage();

        ByteBuffer messageData = new ByteBuffer();
        messageData.appendBytes(submit.getMsgId(), 8);
        messageData.appendString("0", 7);
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmm");
        messageData.appendString(sdf.format(new Date()), 10);
        messageData.appendString(sdf.format(new Date()), 10);
        messageData.appendString(submit.getDestTermId()[0], 32);
        messageData.appendInt(30);

        sm.setMessage(messageData.getBuffer(), (byte) 04);
        delive.setSm(sm);
        delive.setLinkId(submit.getLinkId());

        return delive;

    }
}
